class A < B
,<
就是繼承,A繼承B
。
Ruby是單向繼承,抱歉我用比較粗俗的方式說明,只可以有一個爸爸,但可以有很多小孩。
另外模組不是養父,是爸爸學會了,兒子就會了,模組也不是越多功能越好,能做到幾個相同性質組一個模組最好。還有昨天說明過了,類別方法都會被繼承。
繼承看code就能明白。設定一個類別。
class Protype_monster
attr_accessor :name, :power
def initialize(name = "黑龍", power = rand(800..900))
@name = name
@power = power
end
def final_fight
final_boss
end
protected
def cant_sleep
puts "有睡眠抵抗力"
end
private
def final_boss
puts "我通常在最後一張地圖出現"
end
end
2.7.3 :022 > millaboreus = Protype_monster.new
=> #<Protype_monster:0x00007f88f941b020 @name="黑龍", @power=889>
2.7.3 :023 > p millaboreus
#<Protype_monster:0x00007f88f941b020 @name="黑龍", @power=889>
=> #<Protype_monster:0x00007f88f941b020 @name="黑龍", @power=889>
2.7.3 :024 > millaboreus.final_fight
我通常在最後一張地圖出現
=> nil
millaboreus.cant_sleep #NoMethodError:protected方法不能外篰直接使用。
millaboreus.fly #NoMethodError
millaboreus.environment #NoMethodError
再來是一個子層。
class Elder_dragon < Protype_monster
def fly
puts "滯空#{rand(30..50)}秒"
end
def environment
rand(1..10) > 5 ? (puts "改變環境") : (puts "環境未改變")
end
def resistance
self.cant_sleep
end
end
ksardaora = Elder_dragon.new("鋼龍")
2.7.3 :042 > p ksardaora
#<Elder_dragon:0x00007f88f9412060 @name="鋼龍", @power=850>
=> #<Elder_dragon:0x00007f88f9412060 @name="鋼龍", @power=850>
2.7.3 :043 > puts ksardaora.name
鋼龍
2.7.3 :044 > puts "力量#{ksardaora.power}"
力量850
##子層沒設定的,但父層有,所以繼承沿用,attr_accessor系列,initialize的架構。
2.7.3 :045 > ksardaora.fly
滯空38秒
2.7.3 :046 > ksardaora.environment
環境未改變
#子層的方法,父層無法使用。
ksardaora.final_boss #=>NoMethodError ,private的實體方法不繼承。
2.7.3 :048 > ksardaora.resistance ##protected內的可繼承,所以使用方式正確就可用。
有睡眠抵抗力
可以被很多子類別繼承。
class New_elder_dragon < Elder_dragon
end
class Fly_dragon < Elder_dragon
end
2.7.3 :057 > tigrex = Fly_dragon.new("轟龍", 600)
=> #<Fly_dragon:0x00007f88f93f2e90 @name="轟龍", @power=600>
2.7.3 :058 > tigrex.fly
滯空46秒
2.7.3 :059 > tigrex.environment
環境未改變
最後的類別,爸爸跟爺爺會的自己都會,當然這樣不算好設計,最後的怪物變什麼都會。
順便補充了protected
。
重點在於,單向繼承,利用子類別裡沒有的方法
,Ruby會往父層找的功能(父沒有,會繼續往模組以及父的上層找),子類別可以加入其他更多功能,也不會覺得過於龐大。如有同名方法,看是父或子類別呼叫,以用自己的優先。
與Class
最大差異在於,模組模組間無法繼承,以及無法New
物件,Class
中如果引入模組,其子class
會繼承到父層引入的模組,但無法模組繼承模組,另外Class
的superclass是Module
。
Mixins
:由於Ruby不支援多重繼承,可以以模組來擴充功能,讓子類別越來越完整。
無論Ruby
或在Rails
上,Module
通常會集中放置。
module Elder
def environment
rand(1..10) > 5 ? (puts "改變環境") : (puts "環境未改變")
end
end
module Flight_mode
def stay_in_the_air
puts "滯空#{rand(30..50)}秒"
end
end
module Scared
def scared
puts "被閃光彈嚇到會站著不動"
end
end
module Brute_wyvern
def run_wild
puts "朝向玩家衝撞"
end
def head_hammer
puts "使用頭部攻擊"
end
end
我把一些skill
先模組化。
接著重新設計class
。
class Biology
include Scared ##引入模組
attr_accessor :name, :power
def initialize(name = "食草龍", power = 10)
@name = name
@power = power
end
def behavior
eat()
end
private
def eat
puts "吃草!"
end
end
2.7.3 :045 > herbivore = Biology.new
=> #<Biology:0x00007fc9c13318e0 @name="食草龍", @power=10>
2.7.3 :046 > herbivore.behavior
吃草!
=> nil
2.7.3 :047 > herbivore.scared
被閃光彈嚇到會站著不動
=> nil
初始的class
設計成只有基本功能。
接著第二個類別。
class Velkhana < Biology
include Elder
include Flight_mode #模組引入
def initialize(name = "冰咒龍", power = 650)
@name = name
@power = power
end
def behavior
eat_snow()
end
private
def eat_snow
puts "吃雪!"
end
end
2.7.3 :066 > velkhana = Velkhana.new
=> #<Velkhana:0x00007fc9c1238c18 @name="冰咒龍", @power=650>
2.7.3 :067 > velkhana.behavior
吃雪!
=> nil
2.7.3 :068 > velkhana.environment
環境未改變
=> nil
2.7.3 :069 > velkhana.stay_in_the_air
滯空43秒
=> nil
2.7.3 :070 > velkhana.scared
被閃光彈嚇到會站著不動 ## 引入模組會被繼承,所以它也會被嚇到
velkhana.run_wild #NoMethodError 模組沒引入不能用
velkhana.head_hammer #NoMethodError 模組沒引入不能用
Velkhana.stay_in_the_air #NoMethodError (undefined method `stay_in_the_air' for Velkhana:Class), include方式導入模組,都是實體方法,類別都不能用。
第三個類別
class Brute_wyverns < Biology
include Brute_wyvern
def initialize(name = "惶怒恐暴龍", power = 700)
@name = name
@power = power
end
def behavior
boom()
end
private
def boom
puts "黑色的大黃瓜,超煩人!"
end
end
2.7.3 :089 > savagedeviljho = Brute_wyverns.new
=> #<Brute_wyverns:0x00007fc9c132af18 @name="惶怒恐暴龍", @power=700>
2.7.3 :090 > savagedeviljho.scared
被閃光彈嚇到會站著不動
=> nil
2.7.3 :091 > savagedeviljho.run_wild
朝向玩家衝撞
=> nil
2.7.3 :092 > savagedeviljho.head_hammer
使用頭部攻擊
=> nil
savagedeviljho.environment #沒引入模組,不會這些
savagedeviljho.stay_in_the_air #沒引入模組,不會這些
最後來一個什麼都會的魔王。
class Final_boss < Biology
extend Elder, Flight_mode, Brute_wyvern
end
2.7.3 :097 > Final_boss.run_wild
朝向玩家衝撞
=> nil
2.7.3 :098 > Final_boss.head_hammer
使用頭部攻擊
=> nil
2.7.3 :099 > Final_boss.environment
改變環境
=> nil
2.7.3 :100 > Final_boss.stay_in_the_air
滯空35秒
順便以這份code顯示了,子與父層如有同名方法,可以自行更改做擴充或改變。
def behavior
boom()
end
code中也展示了extend
與include
的差異。extend
引入的模組方法成為類別方法。include
引入的模組方法成為實體方法。
還有一個prepend
下面會說道。
這個不是說引用原則,而是設計上怎麼處理,在設計上難免得同名。
引用才發現同名,請乖乖回頭修改...
module One
def One.say_hi #Modlue_name.method_name
puts "你好喔!"
end
end
module Two
def Two.say_hi #Modlue_name.method_name
puts "我今天很好喔!"
end
end
class Hello
extend One
extend Two
def hello
One.say_hi
Two.say_hi
end
end
2.7.3 :060 > Hello.new.hello
你好喔!
我今天很好喔!
=> nil
有點反向思考,但沒辦法,初期常被問的問題之一。
剛剛我盡量模組寫在上面,這個要反過來寫。
class Hello
prepend One
def say_hi
"你好喔"
end
end
module One
def say_hi
"先呼叫模組的say_hi,再跑到super,也就是父層執行 " + super
end
end
2.7.3 :125 > Hello.new.say_hi
=> "先呼叫模組的say_hi,再跑到super,也就是父層執行 你好喔"
如果沒super
class Hello
prepend One
def say_hi
"你好喔"
end
end
module One
def say_hi
"先呼叫模組的say_hi,沒了"
end
end
2.7.3 :166 > Hello.new.say_hi
=> "先呼叫模組的say_hi,沒了"
如果是改用extend``include
,就沒效果了。
class Hello
extend One
include One
def say_hi
"你好喔"
end
end
module One
def say_hi
"先呼叫模組的say_hi,再跑到super,也就是父層執行 " + super
end
end
2.7.3 :029 > Hello.new.say_hi
=> "你好喔"
2.7.3 :030 > Hello.say_hi
NoMethodError (super: no superclass method `say_hi' for Hello:Class)
簡單點想extend``include``prepend
都是能掛載模組,extend
引入的模組方法成為類別方法。include
引入的模組方法成為實體方法。prepend
能讓class
使用super
方法,使模組運算完的資料再到自己的方法裡處理。
super
...還記得superclass
嗎?
2.7.3 :031 > Array.superclass
=> Object
一開始說明繼承的程式碼,已經顯示super
是不用寫入,Ruby也會自動使用的,那就看看指定使用的方式。
class Top
def self.one #已經開始懶得想方法名了,直接用self代表連new都懶了
"hello, "
end
end
class Child < Top
def self.one
super + "Player!"
end
end
2.7.3 :048 > Child.one
=> "hello, Player!"
對,不是模組prepend
才能用super
,super
本身就是一種方法。
class Super_top
def self.one
"OH! "
end
end
class Top < Super_top
def self.one
super + "hello, "
end
end
class Child < Top
def self.one
super + "Player!"
end
end
2.7.3 :018 > Child.one
=> "OH! hello, Player!"
娛樂性質示範~~
再來,帶參數使用。
class Top
def math(int)
int * 10
end
end
class Child < Top
def math(int)
super * 10
end
end
2.7.3 :012 > Child.new.math(10)
=> 1000
參數是由子傳給父層方法處理。
class Top
def math(int)
int = 5
end
end
class Child < Top
def math(int)
int * super
end
end
2.7.3 :012 > Child.new.math(20)
=> 100
接著是如果不想把參數傳給上層
class Top
def math
40
end
end
class Child < Top
def math(int)
int * super()
end
end
2.7.3 :012 > Child.new.math(20)
=> 800
最後是傳給block
。
class Top
def say_hello
puts "123"
yield
end
end
class Child < Top
def say_hello
puts "456"
super
end
end
2.7.3 :015 > Child.new.say_hello {puts "789"}
789
123
456
呼...
記得require
自己製作的模組不像Math
,雖然Math
也是模組,但已經成為Ruby的標準函式庫了。
可以直接以Module_name.Moudle_method_name
這樣呼叫
2.7.3 :002 > Math.sqrt(16)
=> 4.0
而其實還是可以引入,直接讓irb的空白物件掛載。
:001 > sqrt(16) #這樣不行
NoMethodError (undefined method 'sqrt' for main:Object)
:002 > include Math #這樣後就可以了
=> Object
:003 > sqrt(16)
=> 4.0
第八天的leetcode989. Add to Array-Form of Integer
題目連結:https://leetcode.com/problems/add-to-array-form-of-integer/
題目重點:很簡單,手續比較多而已。
# @param {Integer[]} num
# @param {Integer} k
# @return {Integer[]}
def add_to_array_form(num, k)
end
puts add_to_array_form([1,2,0,0], 34) #=>[1, 2, 3, 4]
puts add_to_array_form([2,7,4], 181) #=>[4, 5, 5]
puts add_to_array_form([2,1,5], 806) #=>[1, 0, 2, 1]
puts add_to_array_form([9,9,9,9,9,9,9,9,9,9], 1) #=>[1,0,0,0,0,0,0,0,0,0,0]
第一個例子其實就把答案說完了。
[1, 2, 0, 0] #=> 1200
:085 > [1, 2, 0, 0].join.to_i
=> 1200
1200 + 34 # Array.join.to_i + k
1234 #=> [1, 2, 3, 4]
:088 > 1234.to_s
=> "1234"
:090 > "1234".split""
=> ["1", "2", "3", "4"]
:091 > ["1", "2", "3", "4"].map{|num| num.to_i}
=> [1, 2, 3, 4]
整理完
def add_to_array_form(num, k)
(num.join.to_i + k).to_s.split("").map(&:to_i)
end
今天提到的
1.類別繼承
2.Module
3.super
方法
4.leetcode989. Add to Array-Form of Integer
明天會解釋&``monkey patch
。
Ruby部分就介紹完嚕!
頭一個禮拜發現篇幅過大,重點容易丟失,之後就都是一個Rails問題跟一題Leetcode了。